/*
 *  UDPFarfetchClient.c
 *  farfetchproject
 *
 *  Created by Rodrigo Souza on 4/18/10.
 *  Copyright 2010 Unicamp. All rights reserved.
 *
 */

#include "ClientProperties.h"
#include "UDPClientConnectionHandler.c"
#include "ClientDataHandler.c"

/* Waits until server response is readable. */
int isReadable(int sd,int * error,int timeOut) { // milliseconds
	fd_set socketReadSet;
	FD_ZERO(&socketReadSet);
	FD_SET(sd,&socketReadSet);
	struct timeval tv;
	if (timeOut) {
		tv.tv_sec  = timeOut / 1000;
		tv.tv_usec = (timeOut % 1000) * 1000;
	} else {
		tv.tv_sec  = 0;
		tv.tv_usec = 0;
	} // if
	if (select(sd+1,&socketReadSet,0,0,&tv) == -1) {
		*error = 1;
		return 0;
	} // if
	*error = 0;
	return FD_ISSET(sd,&socketReadSet) != 0;
}

/* Receive the answer from the server and translates it into interface-readable structure. */
MoviesList* getUDPResponse(int sockfd, int *count, int option) {
	int error, serverLen, nxtMsgSize = 0;
	int timeOut = 100; // ms
	int msgSize = 10;
	struct sockaddr_in responseServer;
	char *sizeMessage = malloc(msgSize);

	//wait until response is readable
	while (!isReadable(sockfd, &error, timeOut));
	
	// Receive next message's size from server
	serverLen = sizeof(responseServer);
	int n = recvfrom(sockfd, sizeMessage, msgSize, 0, (struct sockaddr *) &responseServer, &serverLen);
	sizeMessage[n] = '\0';	
	memcpy(&nxtMsgSize, sizeMessage, sizeof(int));
	
	// Receive data message of server
	char* buffer = malloc((nxtMsgSize + 1) * sizeof(char));
 	n = recvfrom(sockfd, buffer, nxtMsgSize, 0, (struct sockaddr *) &responseServer, &serverLen);
 	buffer[n] = '\0';
	
	//print received message
	//printf("Recebi: recvline:<%s>\n", buffer);
	
	// Retrieve useful info from received data
 	MoviesList* list = getData(buffer, count, option);
	
	return list;
}

/* Creates the socket connection and send the request to the server. */
MoviesList* createConnection(Request* r, int *count) {
	int sockfd;
	struct sockaddr_in servaddr;
	
	//create server socket
 	bzero(&servaddr, sizeof(servaddr));
 	servaddr.sin_family = AF_INET;
 	servaddr.sin_addr.s_addr = inet_addr(SERVER_IP);
 	servaddr.sin_port   = htons(SERVER_PORT);
  	sockfd = Socket(AF_INET, SOCK_DGRAM, 0);

	//send request to server
  	char *re = convertRequest(r);
  	int rc = sendto(sockfd, re, strlen(re), 0, (struct sockaddr *) &servaddr, sizeof(servaddr));
	
	//receive and return response
	return getUDPResponse(sockfd, count, r->option);
}

/* Method called by the interface. Returns the required information. */
MoviesList* executeRequest(Request *r, int *count) {
	return createConnection(r, count);
}
